<template>
  <section class="data-source-config">
    <header class="config-header">
      <a-space>
        <span class="label">数据源类型:</span>
        <a-select
          id="data-source-type"
          v-model="sqlType"
          style="width: 140px;"
          size="small"
          @change="handleChange"
        >
          <a-select-option
            v-for="item in dataSourceTypeOptions"
            :key="item.value"
            :value="item.value"
          >
            <a-icon-font :type="item.icon" /> {{ item.label }}
          </a-select-option>
        </a-select>
        <a-button
          type="primary"
          size="small"
          ghost
          style="border-radius: 4px;"
          @click="configVisible = true"
        >
          数据源配置
        </a-button>
      </a-space>
      <a-space>
        <a-tooltip :title="disabled ? '请先进行数据源配置' : ''">
          <a-button
            type="primary"
            size="small"
            icon="caret-right"
            :loading="iconLoading"
            :disabled="disabled"
            ghost
            style="border-radius: 4px;"
            @click="handleAnalytic"
          >
            解析
          </a-button>
        </a-tooltip>
      </a-space>
    </header>
    <main id="sql-edit-section" ref="sqlEditSection" class="code-section">
      <div v-if="errorShow" class="error-alert">
        <a-tooltip :title="errorMessage" placement="bottom">
          <a-icon-font type="icon-shibai" />
          {{ errorMessage }}
        </a-tooltip>
        <span class="close-icon" @click="closeErrorAlert">
          <a-icon type="close" />
        </span>
      </div>
      <code-editor
        ref="codeEditor"
        class="code-mirror"
        :mode="modeMap[sqlType]"
        :value.sync="codeValue"
        :height="editorHeight"
      ></code-editor>
    </main>

    <data-source-config-modal
      :value.sync="configVisible"
      :connection-result.sync="connectionResult"
      :config="configInfo"
      :sql-type="sqlType"
      @confirm="confirmConfig"
    >
    </data-source-config-modal>
  </section>
</template>

<script lang="ts">
/**
 * 数据源配置
 */
import { Component, Ref } from 'vue-property-decorator'
import dataSourceTypeOptions from '@/components/home/utils'
import {
  DataSourceType,
  DataSourceTypeObject,
} from '@/components/home/interface'
import DataSourceConfigModal from '@/components/home/DataSourceConfigModal.vue'
import CodeEditor from '@/components/vue-codemirror/CodeEditor.vue'
import { parseAllLineageApi } from '@/api/data-lineage'
import CancelRequestMixin from '../cancel-request-mixin'
import DataLineage from '@/store/modules/data-lineage'
import { throttle } from 'lodash'
import { KV } from '@/interface/interface'

const modeMap: KV<string> = {
  MYSQL: 'text/x-mysql',
  POSTGRES: 'text/x-pgsql',
  ORACLE: 'text/x-sql',
  SQLSERVER: 'text/x-sql',
  CLICKHOUSE: 'text/x-clickhouse',
}

@Component({
  name: 'DataSourceConfig',
  components: {
    CodeEditor,
    DataSourceConfigModal,
  },
})
export default class DataSourceConfig extends CancelRequestMixin {
  $eventBus: any
  @Ref('sqlEditSection') sqlEditSection: any
  @Ref('codeEditor') codeEditor: any
  public dataSourceTypeOptions: Array<
    DataSourceTypeObject
  > = dataSourceTypeOptions
  public modeMap: KV<string> = modeMap
  private sqlType: DataSourceType = 'CLICKHOUSE'
  private iconLoading: boolean | { delay: 1000 } = false
  private codeValue: string = ''
  // 编辑器高度
  private editorHeight: any = '0'
  configInfo: any = {
    host: undefined,
    port: undefined,
    username: undefined,
    password: undefined,
    databaseName: undefined,
    schemaName: undefined,
  }
  configVisible: boolean = false
  connectionResult: 'ERROR' | 'SUCCESS' | null = null // null - 未连接， ERROR - 连接失败，SUCCESS - 连接成功
  errorShow: boolean = false // 错误提示显示
  errorMessage: string = '' // 错误提示

  private get disabled() {
    return !this.codeValue
  }

  confirmConfig(config: any) {
    this.configInfo = config
  }

  private handleChange() {
    // this.initConfigInfo()
    // this.codeValue = ''
    this.$eventBus.$emit('clear-graph')
  }

  private initConfigInfo() {
    this.configInfo.host = undefined
    this.configInfo.port = undefined
    this.configInfo.username = undefined
    this.configInfo.password = undefined
    this.configInfo.databaseName = undefined
    this.configInfo.schemaName = undefined
  }

  private handleAnalytic = throttle(() => {
    this._handleAnalytic()
  }, 1000)

  private async _handleAnalytic() {
    try {
      const parameters: any = {
        databaseInfo: {
          sqlType: this.sqlType,
          ...this.configInfo,
        },
        sql: this.codeValue,
      }
      const source: any = this.createCancelTokenSources('LINEAGE_ANALYTIC')
      this.iconLoading = { delay: 1000 }
      DataLineage.setLoading(true)
      // this.$emit('analytic')
      const response: any = await parseAllLineageApi({
        data: parameters,
        cancelToken: source.token,
      })
      const { code, data, message } = response.data
      if (code === 200) {
        this.clearError()
        const {
          tableLineageCanvasInfo = {},
          fieldLineageCanvasInfo = {},
        } = data
        DataLineage.setTableDataLineage(tableLineageCanvasInfo)
        DataLineage.setFieldDataLineage(fieldLineageCanvasInfo)
        this.$eventBus.$emit('analytic-success')
      } else if (code === 300) {
        this.clearError()
        this.$message.error(message || '未知错误！')
        if (data.grammarError) {
          this.dealError(data)
        }
      } else {
        this.clearError()
        this.$message.error(message || '未知错误！')
      }
    } catch (error) {
      console.error(error)
    } finally {
      this.iconLoading = false
      DataLineage.setLoading(false)
    }
  }

  private dealError(errorResult: any) {
    this.errorMessage = errorResult.errorMessage
    this.errorShow = true
    this.resetEditorHeight()
    const markList: any[] = [
      {
        from: { line: errorResult.lineNumber - 1, ch: 0 },
        to: { line: errorResult.lineNumber, ch: 0 },
        options: { className: 'cm-custom-error-highlight' },
      },
    ]
    this.codeEditor.setCodeHighlight(markList)
  }

  private clearError() {
    this.errorMessage = ''
    this.errorShow = false
    this.resetEditorHeight()
    this.codeEditor.clearCodeHighlight()
  }

  public mounted() {
    this.resetEditorHeight()
    window.addEventListener('resize', this.windowResizeEvent)
    this.$once('hook:beforeDestroy', () => {
      window.removeEventListener('resize', this.windowResizeEvent)
    })
  }

  /**
   * 窗口尺寸 resize
   */
  private windowResizeEvent() {
    this.$nextTick(() => {
      this.resetEditorHeight()
    })
  }

  public resetEditorHeight() {
    const errorAlertHeight: number = this.errorShow ? 32 : 0
    this.editorHeight = (
      (this.sqlEditSection as HTMLElement).clientHeight - errorAlertHeight
    ).toString()
  }

  private closeErrorAlert() {
    this.clearError()
  }
}
</script>

<style lang="less" scoped>
@import '../../styles/constants';

.data-source-config {
  background-color: @VIEW_BACKGROUND_COLOR;
  border-right: 1px solid @NEUTRAL_COLOR6;
  height: 100%;
  padding-right: 1px;
  width: 100%;

  .config-header {
    align-items: center;
    border-bottom: 1px solid @NEUTRAL_COLOR6;
    display: flex;
    height: 48px;
    justify-content: space-between;
    line-height: 48px;
    padding: 0 12px;

    .label {
      color: #373b52;
      font-family: PingFangSC-Semibold;
      font-size: 14px;
      letter-spacing: 1px;
    }
  }

  .code-section {
    display: flex;
    flex-direction: column;
    height: calc(100% - 48px);
    position: relative;

    .error-alert {
      background-color: #ffe5e7;
      height: 32px;
      line-height: 32px;
      overflow: hidden;
      padding: 0 34px 0 12px;
      text-align: center;
      text-overflow: ellipsis;
      top: 0;
      white-space: nowrap;
      width: 100%;
      z-index: 100;

      .close-icon {
        cursor: pointer;
        padding: 0 9px;
        position: absolute;
        right: 0;
      }
    }
  }
}
</style>
